#!/usr/bin/env python
# encoding: UTF-8

# TODO: problém s barvami v Game (jen několik barev -> dát možnost vybrat barvu nebo omezit počet hráčů)

__version__ = "$Revision: 14 $"

import cmd
import socket
from threading import Thread
from XMLRPC import XMLRPCServer

# own modules
from game import Player, Game, GameServer



class CLI(cmd.Cmd):
    """xmlrpc is (xmlrpc_server, port)
    xmlrpc_thread is the thread running the server.serve_forever() function
    gserver is GameServer managing the games"""
    xmlrpc = None
    xmlrpc_thread = None
    gserver = None
    
    def __init__(self, server=None):
        """server is the instance of a XML-RPC server used to handle requests.
        If None supplied, the default instance of SimpleXMLRPCServer is used. 
        It doesn't have to be a subclass of SimpleXMLRPCServer, but has to
        respect its interface, that is at least:
        server.register_function()
        server.register_instance() - with support of the _dispatch() method
        server.serve_forever()
        logging to sys.stderr
        
        minport and maxport is the port range where to find a vacant port."""
        
        cmd.Cmd.__init__(self)
        
        # init server
        if server is None:
            server = CLI.make_server()
        self.xmlrpc = [server, server.server_address[1]]
        self.start_server()

        self.prompt = ">"
        self.intro = self.list_servers()
        self.intro += "\nThe admin_code for this server is %s." % self.gserver.admin_code

    def complete_terminate_game(self, text, line, begidx, endidx):
        return [str(x) for x, game in enumerate(self.gserver.games) 
                    if str(x).startswith(text) and game is not None]
    
    def do_exit(self, line=None):
        """Exits the server"""
        return True
    
    def do_EOF(self, line):
        return self.do_exit()
    
    def do_quit(self, line):
        """Exits the server"""
        return self.do_exit()
        
    def do_start_game(self, line):
        """Usage: start_game name map_id [max_players]
        max_players defaults to 2, the other parameters have default values too,
        but this serves mainly for debugging purposes."""
        gserver = self.gserver
        args = line.split()
        id = gserver.new_game(*args)
        print "%s (id %d) started on server at port %d" % (gserver.games[id], 
                                                            id, self.xmlrpc[1])
    def do_remove_player(self, line):
        """Usage: remove_player game_id player_id"""
        gserver = self.gserver
        args = map(int, line.split())
        if len(args) != 2:
            raise TypeError("Bad arguments, see help")
        success = gserver.remove_player(args[0], args[1], gserver.admin_code)
        if success:
            print "Ok"
                                                        
    def do_terminate_game(self, line):
        """Usage: terminate_game game_id"""
        gserver = self.gserver
        success = gserver.terminate_game(int(line), gserver.admin_code)
        if success:
            print "Game %s terminated" % line.strip()
    
    def do_server_list(self, line):
        """Lists running servers"""
        print self.list_servers()
    
    def do_list_games(self, line):
        gserver = self.gserver
        print "id |       jméno hry           |                mapa             | hráčů "
        for game in gserver.list_games():
            print "%3d|%s|%s| %d/%d" % (game[0], game[1].center(27), 
                                        game[2].center(33), game[3], game[4])
    
    def do_list_players(self, line):
        """Usage: list_players game_id"""
        game_id = int(line)
        print " ID  |  jméno"
        for item in self.gserver.list_players(game_id):
            print "%4d | %s" % item
    def list_servers(self):
        if self.xmlrpc is None:
            message = "No server running."
        else:
            message = "Game server running at port"
            assert self.xmlrpc_thread.is_alive()
            message += " %d" % self.xmlrpc[1]
        return message
        
    def do_server_start(self, line):
        """Usage: start_server [port]
        Starts server on the specified port. If omitted, finds first usable port
        in the range 8000..8080."""
        if line.strip() != "":
            self.start_server(minport = int(line), maxport=int(line))
        else:
            self.start_server()

    @staticmethod
    def make_server(ServerClass=XMLRPCServer, kwargs={"logRequests": False}, minport=8000, maxport=8080):
        lasterror = ValueError("Bad port range")
        for i in range(minport, maxport + 1):
            try:
                host = "localhost"
                server = ServerClass((host, i), **kwargs)
                
                print "Server bind to port %d" % i
                return server
            except socket.error, e:
                lasterror = e
                print e, ":", host, i
        
        raise lasterror


    def start_server(self):
        """Starts server in a new thread and registers it's methods."""
        server = self.xmlrpc[0]
        p = Thread(target=server.serve_forever)
        p.setDaemon(True)
        
        #~ server.register_function(lambda: XMLRPCInterface, "system.listMethods")
        server.register_introspection_functions()
        gserver = GameServer()
        server.register_instance(gserver)

        p.start()

        self.xmlrpc_thread = p
        self.gserver =  gserver
        print "Server at port %d is serving" % self.xmlrpc[1]

    def onecmd(self, line):
        try:
            return cmd.Cmd.onecmd(self, line)
        except Exception, e:
            print e
            return False
            

if __name__ == "__main__":
    server = CLI.make_server()
    console = CLI(server=server)
    console.cmdloop()
